package nl.hanze.t23i.gamemodule.game;

import java.awt.Component;
import java.util.HashMap;

import nl.hanze.t23i.gamemodule.extern.AbstractGameModule;

public class TicTacToeGame extends AbstractGameModule 
{

    public static final String GAME_TYPE = Game.GAME_TYPE;

    //private GameView gameView;
    private String nextPlayer;
    private String moveDetails;
    private HashMap<String, Integer> playerResults;

    //added fields for tictactoe
    public static final int EMPTY = 2;
	
    public static final int HUMAN_WIN    = 0;
    public static final int DRAW         = 1;
    public static final int UNCLEAR      = 2;
    public static final int COMPUTER_WIN = 3;
	
	private int[][] board = new int[3][3];
    
    private HashMap<String, Integer> playersSide;
	
	public TicTacToeGame(String playerOne, String playerTwo) {
            super(playerOne, playerTwo);

            moveDetails = null;
            playerResults = new HashMap<String, Integer>();
            playersSide = new HashMap<String, Integer>();

            //gameView = new GameView(playerOne, playerTwo);
            clearBoard();
	}

	@Override
	public void doPlayerMove(String player, String move) throws IllegalStateException {
            super.doPlayerMove(player, move);

            if(!nextPlayer.equals(player))
                throw new IllegalStateException("It is not your turn!");

            try {
                //1. check if is possible to place on field..
                if(moveOk(Integer.parseInt(move))){	
                        //2. place the player on the field..
                        playMove(Integer.parseInt(move));
                }else{
                        illegalPlayerMove(player, Integer.parseInt(move));
                        return;
                }
            } catch (NumberFormatException e) {
                illegalPlayerMove(player, move);
                return;
            }

            //3. check if a player has won..
            if(isAWin(playersSide.get(nextPlayer))) {
                matchStatus = MATCH_FINISHED;
                moveDetails = nextPlayer+" wint!";
                playerResults.put(player, PLAYER_WIN);
                playerResults.put(otherPlayer(player), PLAYER_LOSS);
            }else if(boardIsFull()) {
                matchStatus = MATCH_FINISHED;
                moveDetails = "Gelijkspel";
                playerResults.put(player, PLAYER_DRAW);
                playerResults.put(otherPlayer(player), PLAYER_DRAW);
            }else{
                moveDetails = player + " heeft een zet gedaan.";
                nextPlayer();
            }
	}

	private void illegalPlayerMove(String player, String move) {
		moveDetails = "Illegal move";
		
		throw new IllegalStateException("Ongeldige move van "+player+": "+move);
	}
	private void illegalPlayerMove(String player, int move) {
		illegalPlayerMove(player, move+" ("+(move%3)+","+(move/3)+")");
	}

	@Override
	public String getMatchResultComment() throws IllegalStateException {
		super.getMatchResultComment();
		
		return "Einde match!";
	}

	@Override
	public int getMatchStatus() {
		return matchStatus;
	}

	@Override
	public String getMoveDetails() throws IllegalStateException {
            super.getMoveDetails();
            if(moveDetails == null) {
                    throw new IllegalStateException("Er is geen zet gedaan tijdens deze beurt!");
            }
            return moveDetails;
	}

	@Override
	public String getPlayerToMove() throws IllegalStateException {
		super.getPlayerToMove();
		return nextPlayer;
	}

	@Override
	public int getPlayerResult(String player) throws IllegalStateException {
		super.getPlayerResult(player);
		
		return playerResults.get(player);
	}
	
	@Override
	public int getPlayerScore(String player) throws IllegalStateException {
		super.getPlayerResult(player);
		
		return playerResults.get(player);
	}

	@Override
	public String getTurnMessage() throws IllegalStateException {
		super.getTurnMessage();
		
		String message = null;
		
		if(moveDetails == null) {
			message = "Plaats uw zet; getal tussen de 0 en de 8";
		} else {
			message = moveDetails;
		}
		
		return message;
	}
	
	@Override
	public Component getView() {
		return null;
	}

	@Override
	public void start() throws IllegalStateException {
		super.start();
		
		nextPlayer = playerOne;
		playersSide.put(playerOne, 0);
		playersSide.put(playerTwo, 1);
	}
	
	private void nextPlayer() {
		nextPlayer = otherPlayer(nextPlayer);
	}
	
	private String otherPlayer(String player) {
		return player.equals(playerOne) ? playerTwo : playerOne;
	}
	
	// Simple supporting routines
    private void clearBoard() {
        for(int row = 0; row < board.length; row++){
            for(int col = 0; col < board[row].length; col++){
                place(row, col, EMPTY);
            }
        }
    }
    
    // Play a move, possibly clearing a square
    private void place( int row, int column, int piece ) {
        board[row][column] = piece;
    }
    
    public void playMove(int move) {
        board[move/3][ move%3] = playersSide.get(nextPlayer);
    }
    
    //check if move ok
    public boolean moveOk(int move) {
    	return ( move >= 0 && move <= 8 && board[move/3 ][ move%3 ] == EMPTY );
    }
    
    // Returns whether 'side' has won in this position
    public boolean isAWin( int side ) {
        for(int row = 0; row < board.length; row++){
            if(board[row][0] == side){
                if(board[row][1] == side){
                    if(board[row][2] == side){
                        return true;
                    }
                }
            }
        }
        for(int col = 0; col < board.length; col++){
            if(board[0][col] == side){
                if(board[1][col] == side){
                    if(board[2][col] == side){
                        return true;
                    }
                }
            }
        }
        if((board[0][0] == side) && (board[1][1] == side) && (board[2][2] == side))
            return true;
        else if((board[2][0] == side) && (board[1][1] == side) && (board[0][2] == side))
            return true;
        else
            return false;
    }
    
    private boolean boardIsFull() {
        for(int row = 0; row < board.length; row++){
            for(int col = 0; col < board[row].length; col++){
                if(board[row][col] == EMPTY){
                    return false;
                }
            }
        }
        return true;
    }
}
